#pragma once

template<class T>
class CMemPool
{
public:
	CMemPool(DWORD dwNumBlock = 1) {
		VERIFY(InitializeCriticalSectionAndSpinCount(&m_cs, 2000));
		//InitializeCriticalSection(&m_cs);

		m_pMemBase = VirtualAlloc(NULL, (dwNumBlock * sizeof(BLOCKNODE)), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
		if (m_pMemBase) {
			PBLOCKNODE pNode = reinterpret_cast<PBLOCKNODE>(m_pMemBase);

			m_dwNumBlock = dwNumBlock;
			m_pListFreeBlock = NULL;
			pNode += (dwNumBlock - 1);
			for (DWORD i=0; i<dwNumBlock; i++) {
				pNode->pNext = m_pListFreeBlock;
				m_pListFreeBlock = pNode--;
			}
		} else {
			m_dwNumBlock = 0;
			m_pListFreeBlock = NULL;
		}
	}

	~CMemPool() {
		if (m_pMemBase) {
			VirtualFree(m_pMemBase, 0, MEM_RELEASE);
			m_pMemBase = NULL;
		}

		DeleteCriticalSection(&m_cs);
	}

	T* Alloc() {
		T* pBlock = NULL;

		EnterCriticalSection(&m_cs);
		if (m_pListFreeBlock) {
			PBLOCKNODE pNode = m_pListFreeBlock;
			m_pListFreeBlock = m_pListFreeBlock->pNext;
			pBlock = reinterpret_cast<T *>(&pNode->Data);
		}
		LeaveCriticalSection(&m_cs);

		return pBlock;
	}

	void Free(T* pBlock) {
		if (pBlock) {
			EnterCriticalSection(&m_cs);
			PBLOCKNODE pNode = reinterpret_cast<PBLOCKNODE>((PCHAR)pBlock - FIELD_OFFSET(BLOCKNODE, Data));
			pNode->pNext = m_pListFreeBlock;
			m_pListFreeBlock = pNode;
			LeaveCriticalSection(&m_cs);
		}
	}

	BOOL GetStatus() {
		return m_pMemBase ? TRUE : FALSE;
	}

	DWORD GetNumBlock() {
		return m_dwNumBlock;
	}

protected:
	typedef struct _BLOCKNODE {
		_BLOCKNODE	*pNext;
		T			Data;
		_BLOCKNODE() {
			pNext = NULL;
		}
	} BLOCKNODE, *PBLOCKNODE;

protected:
	CRITICAL_SECTION	m_cs;
	PVOID				m_pMemBase;			// Pointer of start address of memory pool
	DWORD				m_dwNumBlock;		// Number of blocks
	PBLOCKNODE			m_pListFreeBlock;	// Pointer of free list
};
